const utils = {
    /**
     * 获取元素的最终样式值
     * @param {DOMObject} ele  要获取属性的DOM对象
     * @param {string}    attr 要获取的属性名
     * @return {string}   attr样式的值
     */
    // ES6的对象方法的增强版写法 say () {}
    getStyle (ele, attr) {
        if (ele.currentStyle) {
            // IE
            return ele.currentStyle[attr]
        } else {
            return getComputedStyle(ele, false)[attr]
        }
    },
    /**
     * 添加事件监听
     * @param {DOMObject} ele         要添加监听的DOM元素
     * @param {string}    type        事件名称（不带on）
     * @param {function}  fn          事件处理函数
     * @param {boolean}   [isCapture] 可选参数，是否捕获，默认为false（冒泡），true代表捕获阶段
     */
    on (ele, type, fn, isCapture) {
        // 默认值false
        if (isCapture === undefined) isCapture = false
        if (window.attachEvent) {
            ele.attachEvent('on' + type, fn)
        } else {
            ele.addEventListener(type, fn, isCapture)
        }
    },
    /**
     * 移除事件监听
     * @param {DOMObject} ele         要添加监听的DOM元素
     * @param {string}    type        事件名称（不带on）
     * @param {function}  fn          事件处理函数
     * @param {boolean}   [isCapture] 可选参数，是否捕获，默认为false（冒泡），true代表捕获阶段
     */
    off (ele, type, fn, isCapture) {
        if (isCapture === undefined) isCapture = false
        if (window.detachEvent) {
            ele.detachEvent('on' + type, fn)
        } else {
            ele.removeEventListener(type, fn, isCapture)
        }
    },

    /**
     * 实现元素的匀速运动
     * @param {DOMObject} ele 运动的DOM元素
     * @param {string} attr 运动的属性名
     * @param {number} end 运动的终点值，单位px
     * @param {number} duration 运动的总时间，单位ms
     * @param {function} [fn]  运动结束之后的回调函数
     */
    move (ele, attr, end, duration, fn) {
        // 获取起点值
        var start = parseInt(this.getStyle(ele, attr))
        // 计算运动的总距离
        var distance = end - start
        // 计算总步数
        var steps = parseInt(duration / 20)
        // 计算速度：px/step
        var speed = distance / steps
        // 开始运动
        clearInterval(ele.timer) // 开新的定时器之前把上一次的先停止掉
        var n = 0 // 记录当前步数
        // 把定时器的timer写在ele对象的自定义属性上，确保唯一性
        ele.timer = setInterval(function () {
            // 往前走一步
            n++
            ele.style[attr] = start + n * speed + 'px'
            // 判断终点
            if (n === steps) {
                // 步数走完了，到终点了
                clearInterval(ele.timer)
                // 因为js的小数运算可能并不精确，所以在这里手动的拉到终点
                ele.style[attr] = end + 'px'
                // 调用fn，利用逻辑短路，fn有效才调用
                fn && fn()
            }
        }, 20)
    },

    /**
     * 实现元素的缓冲运动
     * @param {DOMObject} ele 运动的DOM元素
     * @param {string} attr 运动的属性名
     * @param {number} end 运动的终点值，单位px
     * @param {function} [fn]  运动结束之后的回调函数
     */
    move1 (ele, attr, end, fn) {
        end = parseInt(end) // 不是很有必要，但是保险起见取整
        // 获取当前位置
        var start = parseInt(this.getStyle(ele, attr))
        // 开启定时器之前先把上一次的清除
        clearInterval(ele.timer)
        ele.timer = setInterval(function () {
            
            // 每一步都要计算剩下距离
            var distance = end - start
            // 计算速度
            // 速度如果是正向运动向上取整，负向的就向下取整
            var speed = distance > 0 ? Math.ceil(distance / 10) : Math.floor(distance / 10)
            // 当前位置往前走，加上一个speed
            start += speed
            ele.style[attr] = start + 'px'
            // 判断终点
            if (start === end) {
                clearInterval(ele.timer)
                fn && fn()
            }
        }, 20)
    },

    /**
     * 获取的是元素到body的坐标
     * @param {DOMObject} ele 获取坐标的元素
     * @return {object} 得到的坐标值 { left, top }
     */
    getBodyPos (ele) {
        var left = 0, top = 0
        while (ele.offsetParent) {
            // 如果有边框边框也要加上
            left += ele.offsetLeft + ele.clientLeft
            top += ele.offsetTop + ele.clientTop
            // 把ele变成他的父级，为下一次计算做准备
            ele = ele.offsetParent
        }
        return { left, top }
    }
}